package edu.arizona.arid.akshen;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;
import java.util.Vector;

import org.json.JSONException;
import org.json.JSONObject;

import edu.arizona.arid.akshen.entity.Log;
import edu.arizona.arid.akshen.entity.Message;

/**
 * Messenger server
 * 
 * @author Sumin Byeon
 */
public final class Server implements ServerDelegate {

	/**
	 * Specifies a port number that the server uses
	 */
	public static final short port = 8099;
	private ServerSocket serverSocket;
	private PrintStream out;

	/**
	 * A list that contains all clients
	 */
	private List<Client> clients;

	/**
	 * Default contructor
	 * 
	 * @throws IOException
	 */
	public Server() throws IOException {
		out = System.out;
		clients = new Vector<Client>();
	}

	/**
	 * Initiates server
	 * 
	 * @throws IOException
	 * @throws JSONException 
	 */
	public void init() throws IOException, JSONException {
		out.println("Initiating server ...");
		serverSocket = new ServerSocket(port);
		out.printf("Listening on %s\n", serverSocket.getLocalSocketAddress());

		while (true) {
			Socket socket = serverSocket.accept();
			Client client = new Client(socket);
			clients.add(client);
			
			new ServerThread(this, client).start();
			out.printf("Client from %s accepted\n", socket.getInetAddress());
			
			//sendMessage(client, new Message(Message.Type.Notification, "Connected to server"));
		}
	}
	
	/**
	 * Receives a message
	 * 
	 * @param message
	 */
	public void messageReceived(Message message) {
		try {
			//message.insert();
			broadcast(message);
			new Log(Log.Type.Event, message.getText()).insert();
		}
//		catch (SQLException e) {
//			e.printStackTrace();
//		}
		catch (IOException e) {
			e.printStackTrace();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Sends a message to a specific client
	 * 
	 * @param client
	 * @param message
	 * @throws IOException
	 * @throws JSONException
	 */
	public void sendMessage(Client client, Message message) throws IOException, JSONException {
		String text = message.getText();
		String user = message.getUser().getFirstname();
				
		JSONObject json = new JSONObject();
		json.put("type", message.getType());
		json.put("user", user);
		json.put("text", text);
		json.put("timestamp", message.getDate());
		
		OutputStream out = client.getOutputStream();
		out.write(json.toString().getBytes());
		out.flush();
	}

	/**
	 * Broadcast a message to everyone
	 * 
	 * @param message
	 * @throws IOException
	 * @throws JSONException 
	 * @throws JSONException 
	 */
	public void broadcast(Message message) throws IOException, JSONException {
		for (Client client : clients) {
			sendMessage(client, message);
		}
		System.out.printf("Broadcast: %s\n", message.getText());
	}

	/**
	 * Terminates server
	 * 
	 * @param client
	 */
	public void disconnected(Client client) {
		try {
			client.disconnect();
			out.printf("Client %s disconnected\n", client);
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			clients.remove(client);
		}
	}
	
	public void exceptionRaised(Exception e) {
		e.printStackTrace();
	}

	/**
	 * Program entry
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		try {
			new Server().init();
		}
		catch (IOException e) {
			e.printStackTrace();
		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void messageReceived(Client from, Message message) {
		// TODO Auto-generated method stub
		
	}
}
